/****************************************************************************************/
/*                                                                     					*/
/*  M16C/62P Group Program Collection                                  					*/
/*                                                                     					*/
/*  FILE NAME : flash.c                         		              					*/
/*  CPU       : This program is the Serial flash boot loader by Xmodem data transfer	*/
/*  HISTORY   : 2006.12.08 Ver 0.01                                    					*/
/*                                                                    	 				*/
/*  Copyright (C) 2006. Renesas Technology Corp.                       					*/
/*  Copyright (C) 2006. Renesas Solutions Corp.                        					*/
/*  All right reserved.                                                					*/
/*                                                                     					*/
/*****************************************************************************************/

/**************************************/
/*    include file                    */
/**************************************/
#include "flash_header.h"
#include "sfr62p.h"
#include "command.h"

/**************************************/
/*    ROM table declaration           */
/*    REJ09B0185-0241 Page 272        */
/**************************************/
#pragma SECTION rom ram_based_rom
const unsigned long Block_Address[BLOCK_NUM][2] = {
	{ 0xFF000, 0xFFFFE },    //Block 0    4KB
	{ 0xFE000, 0xFEFFE },    //Block 1    4KB
	{ 0xFC000, 0xFDFFE },    //Block 2    8KB
	{ 0xFA000, 0xFBFFE },    //Block 3    8KB
	{ 0xF8000, 0xF9FFE },    //Block 4    8KB
	{ 0xF0000, 0xF7FFE },    //Block 5    32KB
	{ 0xE0000, 0xEFFFE },    //Block 6    64KB
	{ 0xD0000, 0xDFFFE },    //Block 7    64KB
	{ 0xC0000, 0xCFFFE },    //Block 8    64KB
	{ 0xB0000, 0xBFFFE },    //Block 9    64KB
	{ 0xA0000, 0xAFFFE },    //Block 10   64KB   //m30627fhp ROM size = 384KB
#if(ROM_SIZE == ROM_SIZE_512KB)
	{ 0x90000, 0x9FFFE },    //Block 11   64KB
	{ 0x80000, 0x8FFFE },    //Block 12   64KB   
#endif   
	{ 0x0F000, 0x0FFFE }     //Block A    4KB    //data flash     
};

/****************************************/
/*    EnterEW0Mode function             */
/****************************************/
#pragma SECTION program ram_based_prg
void EnterEW0Mode( void )
{
	// during flash memory programming, erasing etc
	// the CPU clock frequency should be < 10MHz (with 1 wait state)
	// or < 6.5MHz (no wait state)

	
	asm("fclr i");
	
	// enable access to the clock mode register 1 (CM0)
	prc0 = 1;
	
	// CM1 - System Clock Control Register 1
	//-------------------------------------------------------------------------
	cm17 = 1;				// Main Clock Divide Ratio
	cm16 = 0;				//	CM17	CM16
							//	0		0		- No Division
							//	0		1		- Divide by 2
							//	1		0		- Divide by 4
							//	1		1		- Divide by 16
	
	// disable access to the clock mode register 1 (CM0)
	prc0 = 1;
	
	// CPU now operating at 6MHz
	//
	// enter CPU re-write mode
	fmr01 = 0;				// first write 0 then write 1
	fmr01 = 1;
	
	// set EW0 mode
	fmr11 = 0;
	
	// disable all lock bit protection to allow programming and erase operations
	fmr02 = 0;				// first write 0 then write 1
	fmr02 = 1;
	
	// all flash blocks now unlocked
	//
	// wait while flash is busy
	while( fmr00 == 0 );
}

/****************************************/
/*    ExitEW0Mode function              */
/****************************************/
void ExitEW0Mode( void )
{
	// when this function exits the CPU clock will be 24MHz
	
	// enable the lock-bit protection
	fmr02 = 0;
	
	// exit CPU re-write mode
	fmr01 = 0;
	
	// enable access to the clock mode register 1 (CM0)
	prc0 = 1;
	
	// CM1 - System Clock Control Register 1
	//-------------------------------------------------------------------------
	cm17 = 0;				// Main Clock Divide Ratio
	cm16 = 0;				//	CM17	CM16
							//	0		0		- No Division
							//	0		1		- Divide by 2
							//	1		0		- Divide by 4
							//	1		1		- Divide by 16
	
	// disable access to the clock mode register 1 (CM0)
	prc0 = 0;
	
	asm("fset i");
}

/****************************************/
/*    BlockErase function               */
/****************************************/
unsigned char BlockErase( unsigned long BlockNum, unsigned short *Dummy )
{
	// attempts to erase the block specified by BlockNum
	//
	// returns:
	//
	// ERASE_PASS
	// or
	// ERASE_FAIL
	
	volatile unsigned short _far *p;
	volatile unsigned char Status;
	unsigned long ul;
	volatile unsigned short Tmp;
	
	// check if block needs erasing
	Status = 0;
	p = (volatile unsigned short _far *)Block_Address[ BlockNum ][ 0 ];
	for( ul = Block_Address[ BlockNum ][ 0 ]; ul<Block_Address[ BlockNum ][ 1 ] + 1; ul++ )
	{
		if( *p != 0xffff )
		{
			Status = 1;
			break;
		}
		else
		{
			p++;
		}
	}
	
	if( Status == 0 ) return ERASE_PASS;
	
	EnterEW0Mode();
		
	// write erase block command to even flash address
	p = (volatile unsigned short _far *)Block_Address[ BlockNum ][ 0 ];
	*p = BLOCK_ERASE;
	// write H'xxD0 to upper most address in block to be erased
	p = (volatile unsigned short _far *)Block_Address[ BlockNum ][ 1 ];
	*p = 0x00D0;
	
	// wait while flash is busy
	while( fmr00 == 0 );
	
	// read flash to allow access to the status register
	Tmp = *p;
	
	// read the erase status flag in the status register
	Status = fmr07;
	
	ExitEW0Mode();
	
	if( Status == 0 )
	{
		// flash block erase successful
		return ERASE_PASS;
	}
	else
	{
		// flash block erase failed
		return ERASE_FAIL;
	}
}

/****************************************/
/*    Program_Bytes function        */
/****************************************/
unsigned char Program_Bytes( unsigned long Address, unsigned char length, unsigned short *Data )
{
	// attempts to program N bytes (in word units)
	// at address the specified address
	//
	// returns:
	// 
	// PROG_PASS
	// or
	// PROG_FAIL
	
	unsigned char Count, Status;
	unsigned long Addr;
	volatile unsigned short _far *p;
	volatile unsigned short Tmp;
	
	Count = 0;
	Addr = Address;
	
	EnterEW0Mode();
	
	Status = PROG_PASS;
	while( ( Count < (length / 2) ) && ( Status == PROG_PASS ) )
	{
		p = (volatile unsigned short _far *)Addr;
		*p = PROGRAM_CMD;
		*p = Data[ Count ];
		
		// wait while flash is busy
		while( fmr00 == 0 );
	
		// read flash to allow access to the status register
		Tmp = *p;
		
		// read the erase status flag in the status register
		Status = fmr06;
				
		if( Status == 0 )
		{
			Status = PROG_PASS;
		}
		else
		{
			Status = PROG_FAIL;
		}
		
		Count++;
		Addr += 2;
	}

	ExitEW0Mode();
	
	return Status;
}

